package com.utbm.lo54.dao.neo4j;

import java.util.Set;

import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;

import com.utbm.lo54.dao.ClientDAOInterface;
import com.utbm.lo54.dao.LocationDAOInterface.LocationProperties;
import com.utbm.lo54.entity.Client;
import com.utbm.lo54.entity.Location;
import com.utbm.lo54.entity.Session;

public class Neo4jClientDAO implements ClientDAOInterface{

	@Override
	public Client create(Client cl) {
		Node firstNode;
		Node sessionNode;

		GraphDatabaseService graphDb = Neo4jUtility.getGraphDatabase();

		Transaction tx = graphDb.beginTx();
		try
		{
			Node foundNode=Neo4jUtility.getNodeIndex().get("EMAIL", cl.getEmail()).getSingle();
			if (foundNode!=null) return nodeToClient(foundNode);
			firstNode = Neo4jUtility.createAndIndex("EMAIL",  ""+cl.getEmail());
			clientToNode(cl,firstNode);
			cl.setId(firstNode.getId());
			
			
			sessionNode = graphDb.getNodeById(cl.getSessionId());
			firstNode.createRelationshipTo(sessionNode, Neo4jUtility.RelTypes.SUBSCRIBED);
			
			tx.success();
		}
		finally
		{
			tx.finish();
		}
		return cl;
	}

	private void clientToNode(Client cl, Node firstNode) {
		firstNode.setProperty(ClientProperties.FIRSTNAME.name(), cl.getFirstName());
		firstNode.setProperty(ClientProperties.LASTNAME.name(), cl.getLastName());
		firstNode.setProperty(ClientProperties.ADDRESS.name(), cl.getAddress());
		firstNode.setProperty(ClientProperties.EMAIL.name(), cl.getEmail());
		firstNode.setProperty(ClientProperties.PHONE.name(), cl.getPhone());
		firstNode.setProperty(ClientProperties.TYPE.name(), "USER");
	}

	private Client nodeToClient(Node foundNode) {
		Client cl = new Client();
		cl.setId(foundNode.getId());
		cl.setFirstName((String) foundNode.getProperty(ClientProperties.FIRSTNAME.name()));
		cl.setLastName((String) foundNode.getProperty(ClientProperties.LASTNAME.name()));
		cl.setAddress((String) foundNode.getProperty(ClientProperties.ADDRESS.name()));
		cl.setEmail((String) foundNode.getProperty(ClientProperties.EMAIL.name()));
		cl.setPhone((String) foundNode.getProperty(ClientProperties.PHONE.name()));
		for(Relationship re :foundNode.getRelationships()){
			Node session = re.getOtherNode(foundNode);
			cl.setSessionId(session.getId());
		}
		return cl;
	}

	@Override
	public void delete(Client cl) {
		Node clientNode;
		GraphDatabaseService graphDb = Neo4jUtility.getGraphDatabase();
		Transaction tx = graphDb.beginTx();
		try
		{
			clientNode = graphDb.getNodeById(cl.getId());
			Neo4jUtility.getNodeIndex().remove(clientNode);
			Iterable<Relationship> rels = clientNode.getRelationships(); // Get all the relationships and iterate to delete them one by one
			for(Relationship rel : rels){
				rel.delete();
			}
			clientNode.delete();			
			tx.success();
		}
		finally
		{
			tx.finish();
		}
	}


	@Override
	public Client findById(Long id) {
		Node clientNode;
		GraphDatabaseService graphDb = Neo4jUtility.getGraphDatabase();
		Transaction tx = graphDb.beginTx();
		try
		{
			clientNode = graphDb.getNodeById(id);
			tx.success();
		}
		finally
		{
			tx.finish();
		}
		return nodeToClient(clientNode);
	}

	@Override
	public void update(Client cl) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Set<Client> getAllClient() {
		// TODO Auto-generated method stub
		return null;
	}
}
